package cn.geminis.workflow.service.controller;

import cn.geminis.auth.context.LoginUser;
import cn.geminis.core.util.DateUtils;
import cn.geminis.data.jpa.PageQuery;
import cn.geminis.workflow.service.controller.vo.Process;
import cn.geminis.workflow.service.controller.vo.Task;
import cn.geminis.workflow.service.controller.vo.filter.TaskFilter;
import cn.geminis.workflow.service.service.model.ApproveResultService;
import cn.geminis.workflow.service.service.model.ExtendDbOperateService;
import cn.geminis.workflow.service.utils.QueryUtils;
import cn.geminis.workflow.service.utils.TaskUtils;
import lombok.RequiredArgsConstructor;
import org.flowable.engine.ProcessEngine;
import org.springframework.data.domain.Page;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * @author puddi
 */
@RestController
@RequestMapping("/history")
@RequiredArgsConstructor
public class HistoryController {

    private final ProcessEngine engine;
    private final ExtendDbOperateService extendDbOperateService;
    private final ApproveResultService approveResultService;

    @GetMapping("/process")
    public Page<Process> findPageProcess(final PageQuery pageParameter) {
        var query = this.engine
                .getHistoryService()
                .createHistoricProcessInstanceQuery()
                .orderByProcessInstanceStartTime().desc();

        return QueryUtils.toPage(query, pageParameter, Process.class);
    }

    @DeleteMapping("/process")
    public void deleteProcess(@RequestBody List<String> ids) {
        ids.forEach(id -> {
            this.engine.getHistoryService().deleteHistoricProcessInstance(id);
            this.approveResultService.deleteApprove(id);
        });
    }

    @GetMapping("/process/{processId}/task")
    public List<Task> tasks(@PathVariable String processId) {
        var query = this.engine
                .getHistoryService()
                .createHistoricTaskInstanceQuery()
                .processInstanceId(processId)
                .orderByTaskCreateTime().asc();

        var tasks = QueryUtils.toList(query, Task.class);

        var approves = approveResultService.findByProcessInstanceId(processId);
        TaskUtils.fillTaskInfo(tasks, approves);

        return tasks;
    }

    @GetMapping("/task")
    public Page<Task> tasks(final PageQuery pageParameter, final TaskFilter taskQueryParameter) {
        var query = this.engine
                .getHistoryService()
                .createHistoricTaskInstanceQuery()
                .orderByTaskCreateTime().asc();

        if (!ObjectUtils.isEmpty(taskQueryParameter.getEndTimeBeforeOrEqual())) {
            query.taskCompletedBefore(DateUtils.toDate(taskQueryParameter.getEndTimeBeforeOrEqual()));
        }
        if (!ObjectUtils.isEmpty(taskQueryParameter.getEndTimeAfterOrEqual())) {
            query.taskCompletedAfter(DateUtils.toDate(taskQueryParameter.getEndTimeAfterOrEqual()));
        }
        if (!ObjectUtils.isEmpty(taskQueryParameter.getCreateTimeBeforeOrEqual())) {
            query.taskCreatedBefore(DateUtils.toDate(taskQueryParameter.getCreateTimeBeforeOrEqual()));
        }
        if (!ObjectUtils.isEmpty(taskQueryParameter.getCreateTimeAfterOrEqual())) {
            query.taskCreatedAfter(DateUtils.toDate(taskQueryParameter.getCreateTimeAfterOrEqual()));
        }

        return QueryUtils.toPage(query, pageParameter, Task.class);
    }

    @GetMapping("/task/{taskId}")
    public Task task(@PathVariable String taskId) {
        return extendDbOperateService.getTask(taskId);
    }

    @GetMapping("/myFinished")
    public Page<Task> myFinished(final PageQuery pageParameter) {
        var query = engine
                .getHistoryService()
                .createHistoricTaskInstanceQuery()
                .taskAssignee(LoginUser.fullName())
                .orderByHistoricTaskInstanceEndTime().desc();

        var tasks = QueryUtils.toPage(query, pageParameter, Task.class);

        var approves = approveResultService.findByTaskIds(tasks.map(Task::getId).toList().toArray(new String[0]));
        TaskUtils.fillTaskInfo(tasks.getContent(), approves);

        return tasks;
    }

    @GetMapping("/myStarted")
    public Page<Process> myStarted(final PageQuery pageParameter) {
        var query = engine
                .getHistoryService()
                .createHistoricProcessInstanceQuery()
                .startedBy(LoginUser.fullName())
                .orderByProcessInstanceStartTime().desc();

        return QueryUtils.toPage(query, pageParameter, Process.class);
    }

}
